package io.gitee.zicai.stream.test

import com.github.rholder.retry.Retryer
import com.github.rholder.retry.RetryerBuilder
import com.github.rholder.retry.StopStrategies
import com.github.rholder.retry.WaitStrategies
import io.gitee.zicai.stream.util.LogKit
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.security.SecureRandom
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.TimeUnit
import java.util.function.Supplier
import kotlin.test.BeforeTest
import kotlin.test.Test

/**
 * Test
 * @author zicai
 * @since 2020-05-12
 */
@RunWith(JUnit4::class)
open class Test {

    private lateinit var retryer: Retryer<Any>
    private lateinit var ran: SecureRandom
    private lateinit var excutor: ForkJoinPool

    @Test
    fun test() {
        TimeUnit.MILLISECONDS.toDays(4294967295).also { println(it) }
    }

    @BeforeTest
    fun before() {
        ran = SecureRandom()
        retryer = RetryerBuilder.newBuilder<Any>()
                .retryIfException()
                .retryIfResult { it.toString().toInt() != 3 }
                .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                .withStopStrategy(StopStrategies.stopAfterAttempt(5))
                .build()

        excutor = ForkJoinPool(10)
    }

    @Test
    fun testRetrying() {
        try {
            retryer.call {
                val n = ran.nextInt(10)
                    .also {
                        println("${LogKit.nowTime()} - random number -> $it")
                    }
                if (n == 2) {
                    throw RuntimeException("wrong number 2")
                }
                n
            }
        } catch (e: Exception) {
            println("${LogKit.nowTime()} - cannot get right number, return 0")
            0
        }.also { println("${LogKit.nowTime()} - get number $it") }
    }

    @Test
    fun testCoroutine() {}

    @Test
    fun testThread() {
        println("${LogKit.nowTime()} - ${Thread.currentThread().name}-start...")

        val task1 = CompletableFuture.supplyAsync(Supplier { runTime(5) }, excutor)
                .thenAccept { print("task1", it) }
        val task2 = CompletableFuture.supplyAsync(Supplier { runTime(3) }, excutor)
                .thenAccept { print("task2", it) }
        val task3 = CompletableFuture.supplyAsync(Supplier { runTime(7) }, excutor)
                .thenAccept { print("task3", it) }

        CompletableFuture.allOf(task1, task2, task3).join()

        println("${LogKit.nowTime()} - ${Thread.currentThread().name}-end.")
    }

    private fun runTime(sec: Int): Long {
        return sec.toLong().also { TimeUnit.SECONDS.sleep(it) }
    }

    private fun print(taskName: String, r: Long) {
        System.err.println("${LogKit.nowTime()} - [${Thread.currentThread().name}] - $taskName done! time -> $r sec.")
    }
}